package mod

import (
	"io/ioutil"
	"log"
	"time"
	// "fmt"
	"context"
	"crypto/tls"
	"crypto/x509"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"github.com/go-sql-driver/mysql"
)

func init() {
	// mysql -- 注册 MySQL-TLSConfig
	rootCAs := x509.NewCertPool()
	{
		pem, err := ioutil.ReadFile(CertFile)
		if err != nil {
			log.Fatal(err.Error())
		}
		if ok := rootCAs.AppendCertsFromPEM(pem); !ok {
			log.Fatal("Failed to append PEM.")
		}
	}
	clientCerts := make([]tls.Certificate, 0, 1)
	{
		certs, err := tls.LoadX509KeyPair(CertFile, KeyFile)
		if err != nil {
			log.Fatal(err.Error())
		}
		clientCerts = append(clientCerts, certs)
	}
	mysql.RegisterTLSConfig(CustomTLSKey, &tls.Config{
		RootCAs:            rootCAs,
		Certificates:       clientCerts,
		InsecureSkipVerify: true,
	})
}

// LoginInUNIX 通过 UNIX 连接
func LoginInUNIX() (*sql.DB, error) {
	return sql.Open("mysql", fmt.Sprintf("%s:%s@%s/%s?%s", User, Password, UnixHost, DBName, UnixConfig))
}

// LoginInTCP 通过 TCP 连接
func LoginInTCP() (*sql.DB, error) {
	return sql.Open("mysql", fmt.Sprintf("%s:%s@%s/%s?%s", User, Password, TCPHost, DBName, TCPConfig))
}

// Dial database/sql 配置
func Dial(f LoginInMysql) (*sql.DB, error) {
	var err error
	defaultDB, err = f()
	if err != nil {
		return nil, err
	}

	defaultDB.SetMaxOpenConns(MaxOpenConns) // mariadb default : 100
	defaultDB.SetMaxIdleConns(MaxIdleConns)
	defaultDB.SetConnMaxLifetime(ConnMaxLifetime) // mysql -- 28800

	return defaultDB, nil
}

func Begin() (*sql.Tx, error) {
	return defaultDB.Begin()
}

func BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) {
	return defaultDB.BeginTx(ctx, opts)
}

func Close() error {
	return defaultDB.Close()
}

func Conn(ctx context.Context) (*sql.Conn, error) {
	return defaultDB.Conn(ctx)
}

func Driver() driver.Driver {
	return defaultDB.Driver()
}

func Exec(query string, args ...interface{}) (sql.Result, error) {
	return defaultDB.Exec(query, args...)
}

func ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	return defaultDB.ExecContext(ctx, query, args...)
}

func Ping() error {
	return defaultDB.Ping()
}

func PingContext(ctx context.Context) error {
	return defaultDB.PingContext(ctx)
}

func Prepare(query string) (*sql.Stmt, error) {
	return defaultDB.Prepare(query)
}

func PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
	return defaultDB.PrepareContext(ctx, query)
}

func Query(query string, args ...interface{}) (*sql.Rows, error) {
	return defaultDB.Query(query, args...)
}

func QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
	return defaultDB.QueryContext(ctx, query, args...)
}

func QueryRow(query string, args ...interface{}) *sql.Row {
	return defaultDB.QueryRow(query, args...)
}

func QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
	return defaultDB.QueryRowContext(ctx, query, args...)
}

func SetConnMaxLifetime(d time.Duration) {
	defaultDB.SetConnMaxLifetime(d)
}

func SetMaxIdleConns(n int) {
	defaultDB.SetMaxIdleConns(n)
}

func SetMaxOpenConns(n int) {
	defaultDB.SetMaxOpenConns(n)
}

func Stats() sql.DBStats {
	return defaultDB.Stats()
}
